﻿using System;
//4.10 匿名类型
// 匿名类型是一个由编译器临时创建来存储一组值的简单类。
// 如果要创建一个匿名类型，我们可以使用new关键字，后面加上对象初始化语句，在其中指定该类型包含的属性和值。

namespace _128_匿名类型
{
    class Program
    {
        static void Main(string[] args)
        {
            //例如：
            var dude = new { Name = "Bob", Age = 1 };

            var a1 = new { X = 2, Y = 4 };
            var a2 = new { X = 2, Y = 4 };
            Console.WriteLine(a1.GetType() == a2.GetType()); // 结果为真
            Console.WriteLine(a1 == a2); // 结果为假
            Console.WriteLine(a1.Equals(a2)); // 结果为真

            var dudes = new[]
            {
                new { Name = "Bob", Age = 30 },
                new { Name = "Tom", Age = 30 }
            };
            Console.ReadKey();
        }
    }
    //编译器会将这个语句（近似）转换为以下形式：
    internal class AnonymousGeneratedTypeName
    {
        private string name; //实际的字段名称是无关的
        private int age; //实际的字段名称是无关的
        public AnonymousGeneratedTypeName(string name, int age)
        {
            this.name = name; this.age = age;
        }
        public string Name { get { return name; } }
        public int Age { get { return age; } }
        // 重载了Equals和GetHashCode方法
        // 也重载了ToString方法
    }
    //...
    //var dude = new AnonymousGeneratedTypeName("Bob", 23);
    // 必须使用var关键字来引用一个匿名类型，因为类型的名称是编译器产生的。
    // 匿名类型的属性名可以从本身是一个标识符或以标识符结尾的表达式得到。
    //例如：
    /*
    int Age = 23;
    var dude = new { Name = "Bob", Age, Age.ToString().Length };
    */
    //等同于
    /*
    var dude = new { Name = "Bob", Age = Age, Length = Age.ToString().Length };
    */


    //如果这两个匿名类型实例的元素是相同类型的，并且它们在相同的程序集中声明，那么它们在内部是相同的类型。
    /*
    var a1 = new { X = 2, Y = 4 };
    var a2 = new { X = 2, Y = 4 };
    Console.WriteLine(a1.GetType() == a2.GetType()); // 结果为真
    */
    //此外，匿名类型的Equals方法也被重载了，从而能够执行正确的等于比较运算符
    //Console.WriteLine(a1 == a2); // 结果为假
    //Console.WriteLine(a1.Equals(a2)); // 结果为真
    

    //下面的代码可以创建多个匿名类型数组：
    /*
    var dudes = new[]
    {
        new { Name = "Bob", Age = 30 },
        new { Name = "Tom", Age = 30 }
    };
    */
    //匿名类型主要是在编写LINQ查询时使用，并且是C# 3.0后才出现的特性。
}
